package qc.module.qms.service.producer;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsMQConstant;
import qc.common.core.enums.qms.QmsDataFlowOperateTypeEnum;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.common.core.utils.IdentifierUtil;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.module.qms.dto.mq.QmsMqRawDataMessageDto;
import qc.module.qms.dto.rawdata.QmsRawDataDto;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * QMS原始数据放入MQ生产者Producer，用于原始数据接收Service调用
 *
 * @author QuCheng Tech
 * @since 2025/8/19
 */
@Service
public class QmsRawDataProducer {
    private static final Logger logger = LoggerFactory.getLogger(QmsRawDataProducer.class);

    /**
     * 消息队列中原始数据主题名称
     */
    private static final String MQ_RawData_Topic = QmsMQConstant.MQ_RAWDATA_TOPIC;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private QmsDataFlowLogProducer logProducer;

    /**
     * 同步发送单条原始数据消息
     *
     * @param optype    操作类型
     * @param tablename 原始数据库表名称
     * @param data      原始数据，传入的data中保证原始数据均记录ID不为空
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/10/5
     */
    public String syncSend(QmsDataFlowOperateTypeEnum optype, String tablename, QmsRawDataDto data) {
        List<QmsRawDataDto> datas = new ArrayList<>();
        datas.add(data);

        return syncSend(optype, tablename, datas);
    }

    /**
     * 同步发送多条原始数据消息
     *
     * @param optype    操作类型
     * @param tablename 原始数据库表名称
     * @param datas     原始数据集合，传入的datas中保证每条原始数据均有记录ID
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/10/5
     */
    public String syncSend(QmsDataFlowOperateTypeEnum optype, String tablename, List<QmsRawDataDto> datas) {
        logger.info("syncSend", datas);
        LocalDateTime now = LocalDateTimeUtil.getNow();
        //定义返回结果，默认为是成功
        String result = QCUnifyReturnValue.Success();

        //如果传入的参数错误，不进行提示，也不发送到消息队列中
        if (StringUtils.isBlank(tablename))
            return result;
        if (datas == null || datas.size() < 0x1)
            return result;

        //如果传入的optype错误，自动设置为：接收原始数据
        if (optype != QmsDataFlowOperateTypeEnum.RECEIVE_RAW_DATA
                && optype != QmsDataFlowOperateTypeEnum.PROCESS_RAW_DATA
                && optype != QmsDataFlowOperateTypeEnum.RE_PROCESS_RAW_DATA)
            optype = QmsDataFlowOperateTypeEnum.RECEIVE_RAW_DATA;

        //自动生成一个全局的流程ID，同时也作为节点ID
        String flowid = IdentifierUtil.simpleUUID();
        //根据数据流程操作类型自动判断是否为人工操作
        boolean ismanual = false;
        if (optype != QmsDataFlowOperateTypeEnum.RE_PROCESS_RAW_DATA)
            ismanual = true;
        //默认数据流程日志中的是否成功为false
        boolean issuccess = false;

        QmsMqRawDataMessageDto message = new QmsMqRawDataMessageDto();
        message.setTablecode(tablename);
        message.setDatas(datas);
        message.setFlowid(flowid);
        message.setNodeid(flowid);
        try {
            SendResult sendResult = rocketMQTemplate.syncSend(MQ_RawData_Topic, message);
            SendStatus sendStatus = sendResult.getSendStatus();
            //根据发送至消息队列的结果进行判断，如果发送成功则返回成功（后续的数据处理和保存至数据库均由对应消费者进行），如果发送失败则需要再次直接调用保存到原始数据库方法
            if (sendStatus == SendStatus.SEND_OK) {
                issuccess = true;
            } else {
                //发送失败也记录日志
                //设置数据流程日志中的结果说明为发送消息的状态枚举
                result = sendStatus.name();
            }
        } catch (Exception ex) {
            result = "发送原始数据库表" + tablename + "数据至MQ异常，" + ex.getMessage() + "\r\n";
        }

        //发送数据流程日志消息
        logProducer.sendRawDataFlowLog(flowid, flowid, optype, ismanual, now, null, issuccess, result);

        return result;
    }
}
